package com.feiwo.nonego.rpc.codec;

import com.feiwo.nonego.rpc.common.constants.CommonConstants;
import com.feiwo.nonego.rpc.common.util.SerializationUtils;
import com.feiwo.nonego.rpc.protocol.RpcProtocol;
import com.feiwo.nonego.rpc.protocol.enums.RpcType;
import com.feiwo.nonego.rpc.protocol.header.RpcHeader;
import com.feiwo.nonego.rpc.protocol.request.RpcRequest;
import com.feiwo.nonego.rpc.protocol.response.RpcResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

/**
 * RPC 消息解码
 *
 * @author feiwo 2025-08-05
 */
public class RpcDecoder extends ByteToMessageDecoder implements RpcCodec {
    /**
     * 解码方法，用于将 ByteBuf 中的字节数据解析为 RpcProtocol 对象。
     * <p>
     * 该方法会从 ByteBuf 中读取协议头信息和消息体数据，并根据消息类型（请求、响应、心跳）进行反序列化，
     * 最终构造出对应的 RpcProtocol 对象并添加到输出列表中。
     *
     * @param context 通道处理器上下文，用于处理 I/O 事件或与其他 Handler 交互
     * @param byteBuf 输入的字节缓冲区，包含待解码的数据
     * @param list    输出列表，用于存放解码后的对象
     * @throws Exception 当解码过程中发生异常时抛出
     */
    @Override
    protected void decode(ChannelHandlerContext context, ByteBuf byteBuf, List<Object> list) throws Exception {
        // 判断可读字节数是否小于协议头总长度，如果小于则直接返回，等待更多数据
        if (byteBuf.readableBytes() < CommonConstants.HEADER_TOTAL_LEN) {
            return;
        }
        // 标记当前读索引位置，以便后续回退
        byteBuf.markReaderIndex();

        // 读取魔数字段，判断是否合法
        var magic = byteBuf.readShort();
        if (magic != CommonConstants.MAGIC_NUMBER) {
            throw new IllegalArgumentException("magic number is illegal "+ magic);
        }

        // 依次读取消息类型、状态、消息ID等协议头字段
        var msgType = byteBuf.readByte();
        var status = byteBuf.readByte();
        var msgId = byteBuf.readLong();

        // 读取序列化类型字段，并去除多余空字符
        var serializationTypeBytes = byteBuf.readBytes(SerializationUtils.MAX_SERIALIZATION_TYPE_COUNT);
        var serializationType = SerializationUtils.subString(serializationTypeBytes.toString(StandardCharsets.UTF_8));

        // 读取消息体长度，并判断缓冲区中是否有足够的数据
        var dataLen = byteBuf.readInt();
        if (byteBuf.readableBytes() < dataLen) {
            // 如果数据不足，则重置读索引，等待更多数据
            byteBuf.resetReaderIndex();
            return;
        }

        // 读取实际的消息体数据
        var data = new byte[dataLen];
        byteBuf.readBytes(data);

        // 获取 RPC 消息类型枚举
        var rpcType = RpcType.formType(msgType);
        if (Objects.isNull(rpcType)) {
            return;
        }

        // 构造协议头对象并设置相关字段
        var header = new RpcHeader();
        header.setMagic(magic);
        header.setStatus(status);
        header.setMsgId(msgId);
        header.setMsgType(msgType);
        header.setSerializationType(serializationType);
        header.setMsgLen(dataLen);

        // 获取默认的 JDK 序列化工具
        var serialization = getSerialization(serializationType);

        // 根据消息类型分别处理请求、响应和心跳消息
        switch (rpcType) {
            case REQUEST:
                // 反序列化请求对象
                var request = serialization.deserialize(data, RpcRequest.class);
                if (Objects.nonNull(request)) {
                    // 构造协议对象并添加到结果列表中
                    var protocol = new RpcProtocol<RpcRequest>();
                    protocol.setHeader(header);
                    protocol.setBody(request);
                    list.add(protocol);
                }
                break;
            case RESPONSE:
                // 反序列化响应对象
                var response = serialization.deserialize(data, RpcResponse.class);
                if (Objects.nonNull(response)) {
                    // 构造协议对象并添加到结果列表中
                    var protocol = new RpcProtocol<RpcResponse>();
                    protocol.setHeader(header);
                    protocol.setBody(response);
                    list.add(protocol);
                }
                break;
            case HEARTBEAT:
                // TODO 心跳消息处理逻辑待实现
                break;
        }
    }

}
